window.onload = function () {
  function ShowToast(count) {
    if (count && (count < 0 || isNaN(Number(count)))) {
      throw new Error("count must be a number greater than 0");
    }
    if (ShowToast.instance) return ShowToast.instance;

    /* 定义对象常量 */
    this.POSITIONS = {          // 消息位置 'top', 'center', 'bottom'
      top: 'TOP',
      center: 'CENTER',
      bottom: 'BOTTOM',
    };
    this.TYPES = {              // 消息类型，不同类型会展示不同样式 'primary', 'info', 'success', 'warning', 'error'
      primary: 'PRIMARY',
      info: 'INFO',
      success: 'SUCCESS',
      warning: 'WARNING',
      error: 'ERROR'
    };

    this.count = count || 3;    // 同一个位置区域，最大同时允许存在的消息数量
    this.gap = 16;              // 偏移量
    this.id = 0;                // toast唯一标识
    this.queue = [];            // 控制消息队列
    this.isProcessing = false;  // 添加处理状态锁

    // 检查参数有效性
    this.checkParams = function (message, params) {
      const config = {
        message: '',
        position: 'center',
        duration: 2500,
        type: 'primary'
      };

      if (message === null || message === undefined) {
        config.message = '';
      } else if (typeof message == 'number') {
        config.message = message + '';
      } else if (typeof message == 'string') {
        config.message = message;
      } else {
        throw new Error("message must be string");
      }
      
      if (params) {
        if (Object.prototype.toString.call(params) !== '[object Object]') {
          throw new Error('params must be a plain object');
        }
        if (params.position) {
          if (!['top', 'center', 'bottom'].includes(params.position)) {
            throw new Error("position must be one of 'top', 'center', or 'bottom'.");
          }
          config.position = params.position;
        }
        if (params.duration) {
          if (params.duration < 1000) {
            throw new Error('duration must be greater than 1000');
          }
          config.duration = params.duration;
        }
        if (params.type) {
          if (!this.TYPES[params.type]) {
            throw new Error("type must be one of 'primary', 'info', 'success', 'warning', or 'error'.");
          }
          config.type = params.type;
        }
      }
      
      return config;
    }

    // 检查并创建容器
    this.checkWrap = function () {
      const wrap = document.getElementById('TOAST_WRAP');
      if (!wrap) {
        const toastWrap = document.createElement('div');
        toastWrap.id = 'TOAST_WRAP';

        const CONTAINERS = [
          { ele: null, pos: 'TOP' },
          { ele: null, pos: 'CENTER' },
          { ele: null, pos: 'BOTTOM' },
        ];
        
        const fragment = document.createDocumentFragment();
        CONTAINERS.forEach(v => {
          v.ele = document.createElement('div');
          v.ele.className = `TOAST_CONTAINER TOAST_${v.pos}_CONTAINER`;
          fragment.appendChild(v.ele);
        });
        
        toastWrap.appendChild(fragment);
        document.body.appendChild(toastWrap);
      }
    }

    // 初始化toast
    this.init = function (message, params) {
      const config = this.checkParams(message, params);
      this.checkWrap();
      
      const q = {
        message: config.message,
        position: this.POSITIONS[config.position],
        duration: config.duration,
        type: this.TYPES[config.type],
        id: ++this.id,
        status: 0, // 状态标记 0-已加入队列 1-待添加到容器 2-已添加到容器 3-待移除 4-移除中 5-已移除
      };
      
      this.queue.push(q);
      this.processToast();
    }

    // 处理toast队列
    this.processToast = function () {
      // 如果正在处理队列，直接返回
      if (this.isProcessing) return;
      
      // 清理已移除的toast
      this.queue = this.queue.filter(v => v.status < 5);

      if (this.queue.length === 0) {
        this.isProcessing = false;
        return;
      }

      // 查找待处理的toast
      const queue = this.queue.find(v => v.status === 0);
      if (!queue) {
        this.isProcessing = false;
        return;
      }

      // 设置处理状态
      this.isProcessing = true;

      // 检查当前区域容器有效toast数量 只考虑已添加到容器的toast
      const currentQueue = this.queue.filter(v => v.position === queue.position && v.status === 2);
      const len = currentQueue.length;

      // 如果超出最大数量，移除最早的toast，完成后再添加新的
      if (len >= this.count) {
        const oldestToast = currentQueue[0];
        oldestToast.status = 3;
        this.removeToast(oldestToast, () => {
          // 移除完成后，继续处理队列
          queue.status = 1;
          this.addToast(queue, () => {
            this.isProcessing = false;
            this.processToast();
          });
        });
      } else {
        // 未超出最大数量，直接添加
        queue.status = 1;
        this.addToast(queue, () => {
          this.isProcessing = false;
          this.processToast();
        });
      }
    }

    // 添加toast到容器
    this.addToast = function (queue, callback) {
      const container = document.querySelector(`.TOAST_CONTAINER.TOAST_${queue.position}_CONTAINER`);
      
      // 获取容器中实际存在的toast元素
      const toastElements = Array.from(container.querySelectorAll('.TOAST'))
        .sort((a, b) => parseInt(a.dataset.toastId) - parseInt(b.dataset.toastId));

      // 创建新toast元素
      const toast = document.createElement('div');
      toast.className = `TOAST ${queue.type}`;
      toast.dataset.toastId = queue.id; // 存储ID到dataset

      const text = document.createElement('p');
      text.className = 'TOAST_TEXT';
      text.textContent = queue.message + ' ---- ' + queue.id;
      toast.appendChild(text);

      // 计算位置
      let y = this.gap;
      toastElements.forEach(t => {
        y += t.offsetHeight + this.gap;
      });

      // 设置初始位置（从下方进入）
      toast.style.top = `${y + this.gap}px`;
      container.appendChild(toast);
      queue.status = 2;

      // 触发动画
      setTimeout(() => {
        toast.style.top = `${y}px`;
        toast.classList.add('ACTIVE');
        callback && callback();
      }, 10);

      // 设置自动消失计时器
      setTimeout(() => {
        if (queue.status === 2) { // 确保toast仍然活跃
          queue.status = 3;
          this.removeToast(queue);
        }
      }, queue.duration);
    }

    // 移除toast
    this.removeToast = function (queue, callback) {
      const container = document.querySelector(`.TOAST_CONTAINER.TOAST_${queue.position}_CONTAINER`);
      const toast = container.querySelector(`.TOAST[data-toast-id="${queue.id}"]`);
      
      if (!toast) {
        queue.status = 5;
        callback && callback();
        return;
      }

      // 开始移除动画
      toast.style.opacity = '0';
      toast.style.top = `${parseInt(toast.style.top) - this.gap}px`;
      queue.status = 4;

      // 动画结束后移除元素并调整剩余toast位置
      const onTransitionEnd = () => {
        if (container.contains(toast)) {
          container.removeChild(toast);
          queue.status = 5;
          
          // 重新计算剩余toast位置
          const remainingToasts = Array.from(container.querySelectorAll('.TOAST'))
            .sort((a, b) => parseInt(a.dataset.toastId) - parseInt(b.dataset.toastId));
          
          let y = this.gap;
          remainingToasts.forEach(t => {
            t.style.top = `${y}px`;
            y += t.offsetHeight + this.gap;
          });
          
          callback && callback();
        }
        toast.removeEventListener('transitionend', onTransitionEnd);
      };

      toast.addEventListener('transitionend', onTransitionEnd);
    }
  }

  /**
   * @param {string} message  消息字符串
   * params参数属性：
   * @param {string} position 消息位置
   * @param {number} duration 消息持续时间ms
   * @param {string} type     消息类型
   */
  ShowToast.prototype.show = function (message, params) {
    this.init(message, params);
  }

  window.toast = new ShowToast();
}